#include "myPipeline.h"
#include "myRasterizer.h"
#include "defMath.h"

myPipeline::myPipeline()
: sizeX(800), sizeY(600), DoCull(true), DoClip(true), DoCCW(false),
  zBuffer(NULL), RenderTarget(NULL), Display(NULL), raster(NULL), stats(NULL)
{
	zBuffer = new float[sizeX*sizeY];
	RenderTarget = new color[sizeX*sizeY];
	Display = new rgb[sizeX*sizeY];
	raster = new myRasterizer( this );
	stats = new Stats( this );
}
 
myPipeline::myPipeline(int sx,int sy)
: sizeX(sx), sizeY(sy), DoCull(true), DoClip(true), DoCCW(false),
  zBuffer(NULL), RenderTarget(NULL), Display(NULL), raster(NULL), stats(NULL)
{ 
	printf("\n Construction de myPipeline \n");
	zBuffer = new float[sizeX*sizeY];
	RenderTarget = new color[sizeX*sizeY];
	Display = new rgb[sizeX*sizeY];
	raster = new myRasterizer( this );
	stats = new Stats( this );
}
myPipeline::~myPipeline()
{ 
	
}

/*
ErrCode	myPipeline::DrawTriangle(void *V1, void *V2, void *V3, size_t Id)
{ 
		ErrCode retour = success ;
		_vec3 pt1, pt2, pt3, vec1, vec2, dir;

		float * v1 = (float*)V1;
		float * v2 = (float*)V2;
		float * v3 = (float*)V3;

		pt1.set( v1[0],v1[1],v1[2] );
		pt2.set( v2[0],v2[1],v2[2] );
		pt3.set( v3[0],v3[1],v3[2] );
		vec1 = pt2 - pt1;
		vec2 = pt3 - pt1;
		dir.cross(vec1,vec2);
		if ( !DoCull || DoCCW && dir.z > 0 || !DoCCW && dir.z<0){
			raster->TriangleSetup( (float*&)V1, (float*&)V2, (float*&)V3);
			raster->Rasterize( (float*)V1, (float*)V2,(float*)V3 );
		}
		else
			stats->CulledTri++;
		return retour;
}

ErrCode myPipeline::DrawTriangles(unsigned int nFacettes, unsigned int Offset)
{ 
	ErrCode ret = success;
	void * outV1 = new char[PSstride];
	void * outV2 = new char[PSstride];
	void * outV3 = new char[PSstride];
	for( unsigned int i=Offset; i<nFacettes*3 && i<IndexBufferSize && ret; i+=3 )
	{
		fpVertexShader( (char*)VertexBuffer + IndexBuffer[i] * VSstride, outV1, VSconst, i/3, 0);
		fpVertexShader( (char*)VertexBuffer + IndexBuffer[i+1] * VSstride, outV2, VSconst, i/3, 0);
		fpVertexShader( (char*)VertexBuffer + IndexBuffer[i+2] * VSstride, outV3, VSconst, i/3, 0);
		ret = DrawTriangle( outV1, outV2, outV3, i/3 );
	}
	return ret;
}

bool myPipeline::IsOffScreen(int x, int y)
{ 
	return !( x>=0 && y>=0 && x<sizeX && y<sizeY );
}
void myPipeline::ClearRenderTarget(color Couleur)
{ 
	for( int i=0; i<sizeX*sizeY; i++ )
		RenderTarget[i] = Couleur;
}
void myPipeline::ClearZBuffer(float Zmax)
{ 
	for( int i=0; i<sizeX*sizeY; i++ )
		zBuffer[i] = Zmax;
}
void myPipeline::SetVertexBuffer(unsigned int VBsz, void *VB, unsigned int stride)
{ 
	VertexBufferSize = VBsz ;
	VertexBuffer = VB;
	VSstride = stride;
}
void myPipeline::SetIndexBuffer(unsigned int IBsz, int *IB)
{ 
	IndexBufferSize = IBsz * 3;
	IndexBuffer = IB;
}
void myPipeline::SetVertexShader(fpShader VS)
{ 
	fpVertexShader = *VS;
}
void myPipeline::SetVertexShaderResources(void *Mem)
{ 
	VSconst = Mem;
}
void myPipeline::SetVertexShaderOutput(unsigned int stride, int nSem, InterpSemantic *Sem)
{ 
	PSstride = stride;
	nSemantics = nSem;
	Semantics = Sem;
}	
void myPipeline::SetPixelShader(fpShader PS)
{ 
	fpPixelShader = PS;
}
void myPipeline::SetPixelShaderResources(void *Mem)
{ 
	PSconst = Mem;
}
void myPipeline::SaveRenderTarget(const char *name)
{ 
	FILE *file = fopen( name, "wb" );
	fprintf( file, "P6\n" );
	fprintf( file, "%d %d\n", sizeX, sizeY );
	fprintf( file, "255\n" );
	for( int i=0; i<sizeX*sizeY; i++ )
	{
		Display[i].r = RenderTarget[i].r;
		Display[i].g = RenderTarget[i].g;
		Display[i].b = RenderTarget[i].b;
	}
	fwrite( Display, sizeof(uchar), sizeX*sizeY*3, file );
	fclose( file );

}

void myPipeline::SaveRenderTarget(const char *basename, const int id)
{ 
	char name[255];
	sprintf( name, "%s %d", basename, id );
	SaveRenderTarget( name );
}
/*
void myPipeline::SetRenderState(RenderState rs)
{ 
	switch(rs)
	{
		case RS_Culling:
			DoCull = true;
		break;
		case RS_Filled:
			raster->SetModeFilled();
		break;
		case RS_NoCulling:
			DoCull = false;
		break;
		case RS_OrientationClockWise:
			DoCCW = true;
		break;
		case RS_OrientationCounterClockWise:
			DoCCW = false;
		break;
		case RS_WireFrame:
			raster->SetModeWireframe();
		break;
		default:
		break;
	}
}	*/